import DefaultListableBeanFactory from "@framework/bean/DefaultListableBeanFactory";
import KoaBootLogger from "@framework/web/KoaBootLogger";

/**
 * 属性自动注入
 */

class AutowiredBeanProvider {

    /**
     * 日志
     * @private
     */
    private logger: KoaBootLogger = KoaBootLogger.getInstance();

    /**
     * Bean工厂
     * @private
     */
    private beanFactory: DefaultListableBeanFactory;

    /**
     * 构造方法
     * @param beanFactory
     */
    constructor(beanFactory: DefaultListableBeanFactory) {
        this.beanFactory = beanFactory;
        this.constructorInstance();
        this.autowiringProperty();
    }

    /**
     * 实例化对象
     * @private
     */
    private constructorInstance() {
        this.logger.debug("Loader The BeanDefinition Target Object");
        const beanDefinitions = this.beanFactory.getBeanDefinitions();
        for (let [beanName, beanDefinition] of beanDefinitions) {
            const defaultModule = beanDefinition.getDefaultModule();
            const instance = new defaultModule();
            this.logger.debug(`Loader The ${beanName} Constructor Object Instance`);
            beanDefinition.setInstance(instance);
            this.beanFactory.registerBean(beanName, instance);
        }
        this.beanFactory.registerBean(KoaBootLogger.name, this.logger);
        this.logger.info(`Initializing Ioc Container Ends`);
    }

    /**
     * 实例话属性
     * @private
     */
    private autowiringProperty() {
        this.logger.debug(`Loader The Auto Injection Property And Inject It Into The Instance`)
        const beanDefinitions = this.beanFactory.getBeanDefinitions();
        const singletons = this.beanFactory.getSingleton();

        // 遍历所有 BeanDefinition，获取可注入属性，并执行注入逻辑
        for (const [beanName, beanDefinition] of beanDefinitions) {
            const instance: any = singletons.get(beanName);
            const injectProperty = beanDefinition.getInjectProperty();

            // TODO 自动生成GET、SET方法, 暂不实现
            // const attributeKey = DECORATOR_SUFFIX.generator(beanName, DECORATOR_SUFFIX.PROPERTY);
            // if (Reflect.hasMetadata(attributeKey, beanDefinition.getTarget())) {
            //     const propertyList: KV[] = Reflect.getMetadata(attributeKey, beanDefinition.getTarget());
            //     for (let {key, value} of propertyList) {
            //         instance[`get${value}`] = (): unknown => instance[key];
            //         instance[`set${value}`] = (value: unknown) => instance[key] = value;
            //     }
            // }

            // 如果当前 BeanDefinition 没有可注入属性，则跳过本次循环
            if (!injectProperty) {
                continue;
            }

            // 对于每个可注入属性，检查其依赖的类型是否已被实例化
            for (const property of injectProperty) {
                for (const [propertyKey, propertyType] of property) {

                    this.logger.debug(`Loader ${beanName} Autowiring Property: ${propertyKey}`);

                    // 根据属性类型和名称寻找 Bean，找到则进行注入
                    const autowiredProperty = singletons.get(propertyType) ?? singletons.get(propertyKey);
                    if (!autowiredProperty) {
                        throw new Error(`该类[${beanName}]属性[${propertyKey}]无法注入类型为[${propertyType}]的值，请确保该类型的 Bean 已经被正确注册`)
                    }
                    instance[propertyKey] = autowiredProperty;
                }
            }
        }
        this.logger.info('Auto Injection Property Ends');
    }
}

export default AutowiredBeanProvider;